"""
文件管理器

提供文件组织、移动、复制等管理功能。
"""

import asyncio
import shutil
import os
from typing import Dict, List, Any, Optional, Set
from pathlib import Path
from datetime import datetime
import logging

from src.core.di import Injectable, Inject
from .base import FileInfo, FileCategory, FileType, ScanResult


@Injectable(scope="singleton")
class FileManager:
    """
    文件管理器
    
    提供文件组织、移动、复制、重命名等管理功能。
    """
    
    def __init__(self,
                 config: Dict[str, Any] = Inject("config"),
                 logger: logging.Logger = Inject("logger")):
        self.config = config
        self.logger = logger
        
        # 文件管理配置
        self.manager_config = config.get("file_manager", {})
        self.default_output_structure = self.manager_config.get("output_structure", "category")
        self.create_backup = self.manager_config.get("create_backup", True)
        self.overwrite_existing = self.manager_config.get("overwrite_existing", False)
        self.preserve_timestamps = self.manager_config.get("preserve_timestamps", True)
    
    async def organize_files(self, 
                           files: List[FileInfo], 
                           output_dir: str,
                           structure: str = None,
                           **kwargs) -> Dict[str, Any]:
        """
        组织文件到指定目录结构
        
        Args:
            files: 文件信息列表
            output_dir: 输出目录
            structure: 目录结构类型 (category, type, date, custom)
            **kwargs: 其他参数
        
        Returns:
            组织结果
        """
        self.logger.info(f"组织 {len(files)} 个文件到 {output_dir}")
        
        structure = structure or self.default_output_structure
        output_path = Path(output_dir)
        
        # 创建输出目录
        output_path.mkdir(parents=True, exist_ok=True)
        
        result = {
            "total_files": len(files),
            "processed_files": 0,
            "failed_files": 0,
            "created_directories": set(),
            "file_operations": [],
            "errors": []
        }
        
        try:
            # 根据结构类型组织文件
            if structure == "category":
                await self._organize_by_category(files, output_path, result, **kwargs)
            elif structure == "type":
                await self._organize_by_type(files, output_path, result, **kwargs)
            elif structure == "date":
                await self._organize_by_date(files, output_path, result, **kwargs)
            elif structure == "custom":
                custom_structure = kwargs.get("custom_structure")
                if custom_structure:
                    await self._organize_by_custom(files, output_path, result, custom_structure, **kwargs)
                else:
                    raise ValueError("自定义结构需要提供 custom_structure 参数")
            else:
                raise ValueError(f"不支持的目录结构类型: {structure}")
            
            self.logger.info(f"文件组织完成: 成功 {result['processed_files']}/{result['total_files']}")
            
        except Exception as e:
            error_msg = f"文件组织失败: {e}"
            self.logger.error(error_msg)
            result["errors"].append(error_msg)
        
        # 转换set为list以便JSON序列化
        result["created_directories"] = list(result["created_directories"])
        
        return result
    
    async def _organize_by_category(self, 
                                  files: List[FileInfo], 
                                  output_path: Path, 
                                  result: Dict[str, Any],
                                  **kwargs) -> None:
        """按分类组织文件"""
        
        # 创建分类目录映射
        category_dirs = {
            FileCategory.PRODUCT_DISPLAY: "产品展示",
            FileCategory.PRODUCT_USAGE: "产品使用", 
            FileCategory.MODEL_WEARING: "模特试穿",
            FileCategory.AI_GENERATED: "AI素材",
            FileCategory.BACKGROUND: "背景素材",
            FileCategory.PROMOTIONAL: "宣传素材",
            FileCategory.UNCLASSIFIED: "未分类"
        }
        
        # 允许自定义目录名
        custom_dirs = kwargs.get("category_dirs", {})
        category_dirs.update(custom_dirs)
        
        for file_info in files:
            try:
                # 确定目标目录
                category_dir = category_dirs.get(file_info.category, "未分类")
                target_dir = output_path / category_dir
                
                # 创建目录
                target_dir.mkdir(parents=True, exist_ok=True)
                result["created_directories"].add(str(target_dir))
                
                # 移动或复制文件
                operation = await self._move_or_copy_file(
                    file_info, target_dir, kwargs.get("operation", "copy")
                )
                
                result["file_operations"].append(operation)
                result["processed_files"] += 1
                
            except Exception as e:
                error_msg = f"处理文件失败 {file_info.name}: {e}"
                self.logger.error(error_msg)
                result["errors"].append(error_msg)
                result["failed_files"] += 1
    
    async def _organize_by_type(self, 
                              files: List[FileInfo], 
                              output_path: Path, 
                              result: Dict[str, Any],
                              **kwargs) -> None:
        """按文件类型组织文件"""
        
        type_dirs = {
            FileType.VIDEO: "视频",
            FileType.AUDIO: "音频",
            FileType.IMAGE: "图片",
            FileType.UNKNOWN: "其他"
        }
        
        # 允许自定义目录名
        custom_dirs = kwargs.get("type_dirs", {})
        type_dirs.update(custom_dirs)
        
        for file_info in files:
            try:
                # 确定目标目录
                type_dir = type_dirs.get(file_info.file_type, "其他")
                target_dir = output_path / type_dir
                
                # 创建目录
                target_dir.mkdir(parents=True, exist_ok=True)
                result["created_directories"].add(str(target_dir))
                
                # 移动或复制文件
                operation = await self._move_or_copy_file(
                    file_info, target_dir, kwargs.get("operation", "copy")
                )
                
                result["file_operations"].append(operation)
                result["processed_files"] += 1
                
            except Exception as e:
                error_msg = f"处理文件失败 {file_info.name}: {e}"
                self.logger.error(error_msg)
                result["errors"].append(error_msg)
                result["failed_files"] += 1
    
    async def _organize_by_date(self, 
                              files: List[FileInfo], 
                              output_path: Path, 
                              result: Dict[str, Any],
                              **kwargs) -> None:
        """按日期组织文件"""
        
        date_format = kwargs.get("date_format", "%Y/%m")  # 默认按年/月
        
        for file_info in files:
            try:
                # 使用修改时间或创建时间
                file_date = file_info.modified_time or file_info.created_time
                if not file_date:
                    file_date = datetime.now()
                
                # 格式化日期路径
                date_path = file_date.strftime(date_format)
                target_dir = output_path / date_path
                
                # 创建目录
                target_dir.mkdir(parents=True, exist_ok=True)
                result["created_directories"].add(str(target_dir))
                
                # 移动或复制文件
                operation = await self._move_or_copy_file(
                    file_info, target_dir, kwargs.get("operation", "copy")
                )
                
                result["file_operations"].append(operation)
                result["processed_files"] += 1
                
            except Exception as e:
                error_msg = f"处理文件失败 {file_info.name}: {e}"
                self.logger.error(error_msg)
                result["errors"].append(error_msg)
                result["failed_files"] += 1
    
    async def _organize_by_custom(self, 
                                files: List[FileInfo], 
                                output_path: Path, 
                                result: Dict[str, Any],
                                custom_structure: Dict[str, Any],
                                **kwargs) -> None:
        """按自定义结构组织文件"""
        
        for file_info in files:
            try:
                # 根据自定义规则确定目标路径
                target_path = self._evaluate_custom_path(file_info, custom_structure)
                target_dir = output_path / target_path
                
                # 创建目录
                target_dir.mkdir(parents=True, exist_ok=True)
                result["created_directories"].add(str(target_dir))
                
                # 移动或复制文件
                operation = await self._move_or_copy_file(
                    file_info, target_dir, kwargs.get("operation", "copy")
                )
                
                result["file_operations"].append(operation)
                result["processed_files"] += 1
                
            except Exception as e:
                error_msg = f"处理文件失败 {file_info.name}: {e}"
                self.logger.error(error_msg)
                result["errors"].append(error_msg)
                result["failed_files"] += 1
    
    def _evaluate_custom_path(self, file_info: FileInfo, structure: Dict[str, Any]) -> str:
        """评估自定义路径"""
        
        # 支持模板变量
        variables = {
            "category": file_info.category.value,
            "type": file_info.file_type.value,
            "extension": file_info.extension,
            "year": file_info.modified_time.year if file_info.modified_time else datetime.now().year,
            "month": file_info.modified_time.month if file_info.modified_time else datetime.now().month,
            "size_mb": int(file_info.size / (1024 * 1024))
        }
        
        # 添加元数据变量
        variables.update(file_info.metadata)
        
        # 评估路径模板
        path_template = structure.get("path_template", "{category}")
        
        try:
            return path_template.format(**variables)
        except KeyError as e:
            self.logger.warning(f"自定义路径模板中缺少变量 {e}, 使用默认路径")
            return file_info.category.value
    
    async def _move_or_copy_file(self, 
                               file_info: FileInfo, 
                               target_dir: Path, 
                               operation: str) -> Dict[str, Any]:
        """移动或复制文件"""
        
        source_path = Path(file_info.path)
        target_path = target_dir / source_path.name
        
        # 处理文件名冲突
        if target_path.exists() and not self.overwrite_existing:
            target_path = self._resolve_name_conflict(target_path)
        
        # 创建备份
        if self.create_backup and target_path.exists():
            backup_path = target_path.with_suffix(target_path.suffix + ".backup")
            shutil.copy2(str(target_path), str(backup_path))
        
        # 执行操作
        if operation == "move":
            shutil.move(str(source_path), str(target_path))
            operation_type = "moved"
        else:  # copy
            shutil.copy2(str(source_path), str(target_path))
            operation_type = "copied"
        
        # 保持时间戳
        if self.preserve_timestamps and source_path.exists():
            stat = source_path.stat()
            os.utime(str(target_path), (stat.st_atime, stat.st_mtime))
        
        return {
            "operation": operation_type,
            "source": str(source_path),
            "target": str(target_path),
            "timestamp": datetime.now().isoformat()
        }
    
    def _resolve_name_conflict(self, target_path: Path) -> Path:
        """解决文件名冲突"""
        
        base_name = target_path.stem
        extension = target_path.suffix
        parent = target_path.parent
        
        counter = 1
        while True:
            new_name = f"{base_name}_{counter}{extension}"
            new_path = parent / new_name
            if not new_path.exists():
                return new_path
            counter += 1
    
    async def create_directory_structure(self, base_path: str, structure: Dict[str, Any]) -> List[str]:
        """创建目录结构"""
        
        base_path = Path(base_path)
        created_dirs = []
        
        def create_dirs(current_path: Path, structure_dict: Dict[str, Any]):
            for name, content in structure_dict.items():
                dir_path = current_path / name
                dir_path.mkdir(parents=True, exist_ok=True)
                created_dirs.append(str(dir_path))
                
                if isinstance(content, dict):
                    create_dirs(dir_path, content)
        
        create_dirs(base_path, structure)
        
        self.logger.info(f"创建了 {len(created_dirs)} 个目录")
        return created_dirs
    
    async def cleanup_empty_directories(self, base_path: str) -> List[str]:
        """清理空目录"""
        
        base_path = Path(base_path)
        removed_dirs = []
        
        # 从最深层开始清理
        for root, dirs, files in os.walk(str(base_path), topdown=False):
            root_path = Path(root)
            
            # 跳过基础目录
            if root_path == base_path:
                continue
            
            # 检查目录是否为空
            try:
                if not any(root_path.iterdir()):
                    root_path.rmdir()
                    removed_dirs.append(str(root_path))
                    self.logger.debug(f"删除空目录: {root_path}")
            except OSError:
                # 目录不为空或无权限删除
                pass
        
        self.logger.info(f"清理了 {len(removed_dirs)} 个空目录")
        return removed_dirs
